package com.foogui.faw.oa.listener.service;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.foogui.faw.oa.domain.AuditApproveDO;
import com.foogui.faw.oa.domain.AuditTrailDO;
import com.foogui.faw.oa.domain.PolicyDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class ProcessApiServiceImpl implements ProcessApiService {


    @Override
    public String listenerBPMCallBack(Object request) {

        log.info("listenerBPMCallBack() 监听工作流回调 参数 request={}", request);

        JSONObject entity = JSONUtil.parseObj(request);
        // 获取消息类型
        String messageType = entity.getStr("type");
        // 获取详细信息
        JSONObject interfaceParam = entity.getJSONObject("interfaceParam");
        // 获取Execution对象json
        JSONObject execution = interfaceParam.getJSONObject("execution");
        // 获取业务主键
        String businessKey = execution.getStr("businessKey");

        // todo: 这里需要加分布式锁和select审核授权实体的审批状态进行幂等控制，
        //  例如只有是运营审核的才会在流程结束回调中向EP发送入账信息
        String key = "rebate:BPMCallBack:lock:" + businessKey;

        // 节点动作监听（空)
        if ("message_send".equals(messageType)) {
            return this.doMessageSendListener(entity);
        } else if ("service_callback".equals(messageType)) {
            // 流程自动调用服务（空）
            return this.doServiceCallBackListener(entity);
        } else if ("process_listener".equals(messageType)) {
            // 流程结束时间监听（审批结果）
            return this.doProcessListener(entity);
        } else {
            return null;
        }
    }

    /*
     * 流程监听：流程级别的监听，整个流程结束时候会接到消息
     * 第一种正常通过结束情况，如果流程监听事件为结束end，且结束原因为空，在此种情况下设置单据状态为通过，给流程提交人发送流程通过消息。
     * 第二种被驳回情况，如果流程监听事件为结束end，且结束原因为REJECTTOSTART，在此种情况下设置单据状态为驳回，给流程提交人发送流程驳回消息。
     * @param entity json格式的参数 由BPM发送 需要转化成JSONObject处理
     * @return JSONObject格式 包含status msgCode msg
     * 成功示例{"status":"1","msgCode":"200","msg":"操作成功"}
     */
    private String doProcessListener(JSONObject entity) {

        // 获取详细信息
        JSONObject interfaceParam = entity.getJSONObject("interfaceParam");
        // 获取Execution对象json
        JSONObject execution = interfaceParam.getJSONObject("execution");
        // 当前流程所属应用
        String source = entity.getStr("appsource");
        // 分类标识
        String category = execution.getStr("category");
        // 详细信息中当前任务实例内容
        JSONObject task = interfaceParam.getJSONObject("task");
        // 如果流程监听事件为结束 end 且结束原因为空 那么就是正常通过结束
        String approveId = execution.getStr("businessKey");

        // AuditApproveDO auditApproveDO = auditApproveService.getById(approveId);
        AuditApproveDO auditApproveDO = new AuditApproveDO();
        // todo：流程通过
        if ("end".equals(execution.getStr("eventName")) &&
                (StringUtils.isEmpty(execution.getStr("deleteReason")) || "null".equals(execution.getStr("deleteReason")))
        ) {
            String bizId = auditApproveDO.getBizId();
            log.info("审批结束节点信息：{}", entity);
            if ("商务政策配置政策审批".equals(execution.getStr("templateName"))) {
                // PolicyDO policyDO = policyService.getById(bizId);
                // todo:整个流程结束了，可以执行一些业务逻辑

            } else if ("商务政策入账审批".equals(execution.getStr("templateName"))) {
                // 发送入账信息
                // rebateDataRemote.applyEntryAccount(ExecFormalCalcHistoryDTO.builder().id(id).build());
            }

        }
        // todo:流程被驳回
        if ("end".equals(execution.getStr("eventName"))
                && ("REJECTTOSTART".equals(execution.getStr("deleteReason")))) {

            String bizId = auditApproveDO.getBizId();

            if ("商务政策配置政策审批".equals(execution.getStr("templateName"))) {
                // PolicyDO policyDO = policyService.getById(id);
                // 将政策状态恢复到审批前的状态（配置完成）
                // policyDO.setVfinishstate("01");
            } else if ("商务政策入账审批".equals(execution.getStr("templateName"))) {
                // 更新政策计算历史的状态为"55"驳回
            }
        }


        log.info("----------------listenerBPMCallBack----------processlistener----------------");
    return "ok";
    }

    /*
     * 调用服务监听：根据servicecode区分服务节点所调用的服务，只有使用服务节点时才需要这个监听
     * 这里的servicecode就是在流程模板中服务节点上配置的服务code
     * @param entity json格式的参数 由BPM发送 需要转化成JSONObject处理
     * @return JSONObject格式 包含status msgCode msg
     * 成功示例{"status":"1","msgCode":"200","msg":"操作成功"}
     */
    private String doServiceCallBackListener(JSONObject entity) {
        log.info("----------------listenerBPMCallBack----------callBackService----------------");
        return "ok";
    }


    /*
     * 节点动作监听：任务被创建时向当前任务参与者推送待办消息，根据报文消息判断流程是否为创建状态，同时设置业务对象为审批中状态
     * 一个应用只需要注册一个节点动作监听
     * 即使有多个分类，也使用一个监听（在工作流服务配置中每个分类也都配置这个监听），达到中转分发的效果
     * @param entity json格式的参数 由BPM发送 需要转化成JSONObject处理
     * @return JSONObject格式 包含status msgCode msg
     * 成功示例{"status":"1","msgCode":"200","msg":"操作成功"}
     */

    /**
     * 流程节点监听
     *
     * @param entity 实体
     * @return {@link String}
     */
    private String doMessageSendListener(JSONObject entity) {
        // 返回值波形
        String result = "成功";
        // 获取详细信息
        JSONObject interfaceParam = entity.getJSONObject("interfaceParam");
        // 当前流程所属应用
        String source = entity.getStr("appsource");
        // 详细信息中-流程实例内容
        JSONObject execution = interfaceParam.getJSONObject("execution");
        // 详细信息中-当前任务实例内容
        JSONObject task = interfaceParam.getJSONObject("task");


        //!!!!!!!! 节点动作监听-------向对应审批人推送待办消息!!!!!!!!!!!!!!!!!!!
        // 1 判断当前收到的task消息 当前任务的事件是否为创建事件 如果是创建，说明任务生成，应该向参与者推送待办消息
        // 2 获取流程实例和任务实例中所需要的的信息 然后查询对应的业务对象信息组合为消息推送
        if ("create".equals(task.getStr("eventName"))) {
            //  获取当前节点名称(对应流程节点的名字)
            String taskName = task.getStr("name");
            // 当前任务id
            String taskId = task.getStr("id");
            // 当前任务用户
            String assignee = task.getStr("assignee");
            // 流程摘要信息
            String processName = execution.getStr("name");
            // 组合消息并发送 此处实现以业务应用需求为准 此处仅为举例
            String message = assignee + "你好，流程：" + processName + "中的任务：" + taskName + "请您处理！";
            //  todo：消息推送
        } else if ("complete".equals(task.getStr("eventName"))) {
            // 获取审批模板名称
            if ("商务政策配置政策审批".equals(execution.getStr("templateName"))) {
                String approveId = execution.getStr("businessKey");
                // 获取审批实体对象
                // AuditApproveDO auditApproveDO = auditApproveService.getById(approveId);
                AuditApproveDO auditApproveDO = new AuditApproveDO();

                // 获取业务主键
                String policyId = auditApproveDO.getBizId();
                // todo：通过审批实体对象获取到业务主键，进行相关的业务逻辑处理
                // PolicyDO policyDO = policyService.getById(policyId);

                AuditTrailDO trailDO = createAuditTrail(task, approveId);

                PolicyDO policyDO = new PolicyDO();
                // "总监审批"——对应流程节点名称
                if ("20".equals(policyDO.getVfinishstate()) && "总监审批".equals(task.getStr("name"))) {
                    policyDO.setVfinishstate("21");
                    trailDO.setAuditStatus("21");
                } else if ("21".equals(policyDO.getVfinishstate()) && "商务政策经理审批".equals(task.getStr("name"))) {
                    policyDO.setVfinishstate("22");
                    trailDO.setAuditStatus("22");
                } else if ("22".equals(policyDO.getVfinishstate()) && "销售计划部审批".equals(task.getStr("name"))) {
                    policyDO.setVfinishstate("23");
                    trailDO.setAuditStatus("23");
                    // todo:审核完毕，可以给提交人触发待办任务(当然也可以在流程完成结束时的监听进行发送待办的逻辑)
                }

                // 保存审核轨迹
                // auditTrailService.save(trailDO);
                // 修改政策状态
                // policyService.saveOrUpdate(policyDO);

            } else if ("商务政策入账审批".equals(execution.getStr("templateName"))) {
                // 获取审批流bizId
                String approveId = execution.getStr("businessKey");
                AuditApproveDO auditApproveDO = new AuditApproveDO();
                // AuditApproveDO auditApproveDO = auditApproveService.getById(approveId);
                String historyId = auditApproveDO.getBizId();
                // 获取正式计算历史
                // ExecFormalCalcHistoryDO execFormalCalcHistoryDO = execFormalCalcHistoryService.getSimpleDataById(historyId);

                if ("入账审批-部门".equals(task.getStr("name"))) {
                    // execFormalCalcHistoryDO.setFinEntryState("51部门审核");
                } else if ("入账审批-运营".equals(task.getStr("name"))) {
                    // execFormalCalcHistoryDO.setFinEntryState("52运营审核");
                }

                AuditTrailDO trailDO = createAuditTrail(task, approveId);


                // auditTrailService.save(trailDO);
                // 更改正式计算历史状态
                // execFormalCalcHistoryService.updateById(execFormalCalcHistoryDO);
            }


            // 当前任务已完成，如果此时有需要可增加业务处理，例如通知流程发起人当前节点已经由某人审核通过
            //  todo：消息推送
        }
        return result;
    }

    private AuditTrailDO createAuditTrail(JSONObject task, String approveId) {
        AuditTrailDO trailDO = new AuditTrailDO();
        trailDO.setAuditType("配置审核");
        trailDO.setAuditApprovedId(approveId);

        trailDO.setAuditTime(new Date());
        // 审批人
        trailDO.setSubmitCode(task.getStr("assignee"));
        trailDO.setUserName(task.getStr("assignee"));
        trailDO.setFullMessage("");
        return trailDO;
    }
}
